package com.hd123.rumba.upgrade;

import java.util.ArrayList;
import java.util.List;

import net.sf.hibernate.cfg.Configuration;

import com.hd123.rumba.cartridge.biz.IBCartridgeMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.log.RumbaLogger;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.upgrade.impl.UpgradeSearcher;
import com.hd123.rumba.util.Version;

/**
 * 安装/升级入口 | 实现类
 * <p>
 * 例如：
 * <p>
 * 运行方式一(指定升级类的升级模式)： java com.hd123.rumba.upgrade.UpgEntry
 * /rumba.xml;/myrumba.xml com.hd123.rumba.upgrade.v20.r00.RB_v00r00_Oracle
 * [initData]
 * <p>
 * 运行方式二(自适应的升级模式)： java com.hd123.rumba.upgrade.UpgEntry
 * /rumba.xml;/myrumba.xml
 * 
 * 
 * @author lxg
 * 
 */
public class UpgEntry {

  private String cfgFiles;
  private String upgradeMode;
  private String upgradeName;
  private RumbaLogger logger;
  private String dbms;

  public static void main(String[] args) throws Exception {
    if (args.length < 1 || args.length > 3) {
      printError();
      System.exit(0);
    }

    UpgEntry entry = new UpgEntry();
    entry.cfgFiles = args[0];
    if (args.length >= 2)
      entry.upgradeName = args[1];
    entry.upgradeMode = CUpgrade.UPGRADEMODE_UPGRADE;
    if (args.length >= 3 && "initData".equalsIgnoreCase(args[2]))
      entry.upgradeMode = CUpgrade.UPGRADEMODE_INITDATA;
    entry.logger = RumbaLogger.getLogger(UpgEntry.class);

    try {
      entry.execute();
    } catch (Exception e) {
      entry.logger.error("安装/升级发生异常：", e);
    } finally {
      try {
        HibernateSession.closeSession();
      } catch (Exception e) {
        entry.logger.error("关闭Session出错：", e);
      }
    }
  }

  public void execute() throws Exception {
    com.hd123.rumba.runtime.Configuration.getInstance().config(cfgFiles);
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);

    List<Upgrade> upgrades = getUpgradeList();
    if (upgrades.size() == 0) {
      logger.info("没有需要运行的升级包。");
      return;
    }
    logger.info("查找并运行如下升级包(运行模式：" + upgradeMode + "):");
    for (int i = 0; i < upgrades.size(); i++)
      logger.info(upgrades.get(i).getClass().getName());
    dbms = fetchDBMS();

    // 检查第一个升级版本是否与数据库版本匹配
    if (upgrades.size() > 0) {
      Upgrade firstUpgrade = upgrades.get(0);
      Version dbVersion = cartMgr.getDBVersion(firstUpgrade.getCartUuid());
      if (CUpgrade.UPGRADEMODE_UPGRADE.equals(upgradeMode)) {
        if (!firstUpgrade.getBaseVersion().truncate(3).equals(dbVersion.truncate(3)))
          throw new BusinessException(firstUpgrade.getCartUuid() + "的版本[" + dbVersion
              + "]不是指定的安装/升级包[" + firstUpgrade.getClass().getName() + "]的基准版本，不能执行升级！");
      }
    }

    // 设置为升级状态
    if (CUpgrade.UPGRADEMODE_UPGRADE.equals(upgradeMode))
      for (Upgrade upgrade : upgrades)
        cartMgr.beginUpgradeT(upgrade.getCartUuid());

    // 运行升级包
    if (CUpgrade.UPGRADEMODE_UPGRADE.equals(upgradeMode)) {
      for (Upgrade upgrade : upgrades)
        runUpgrade(upgrade, true, false);
    }
    for (Upgrade upgrade : upgrades)
      runUpgrade(upgrade, false, true);

    // 更新数据库版本号
    if (CUpgrade.UPGRADEMODE_UPGRADE.equals(upgradeMode)) {
      for (Upgrade upgrade : upgrades) {
        cartMgr.endUpgradeT(upgrade.getCartUuid(), upgrade.getTargetVersion());
        logger.info("更新[" + upgrade.getCartUuid() + "] 版本号为"
            + upgrade.getTargetVersion().toString());
      }
    }
  }

  private void runUpgrade(Upgrade upgrade, boolean upgradeDdl, boolean upgradeData)
      throws Exception {
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);
    logger.info("执行安装/升级包[" + upgrade.getClass().getName() + "]");
    HibernateSession.closeSession();
    com.hd123.rumba.runtime.Configuration.getInstance().config(cfgFiles);

    try {
      Version dbVersion = cartMgr.getDBVersion(upgrade.getCartUuid());
      // 运行升级包
      upgrade.run(dbms, upgradeDdl, upgradeData, dbVersion);
    } finally {
      HibernateSession.closeSession();
    }
  }

  private List<Upgrade> getUpgradeList() throws Exception {
    List<Upgrade> upgrades = new ArrayList<Upgrade>();
    if (upgradeName != null) {
      try {
        Upgrade upgrade = (Upgrade) Class.forName(upgradeName).newInstance();
        upgrades.add(upgrade);
      } catch (Exception e) {
        logger.error("加载类" + upgradeName + "出错。");
        throw e;
      }
    } else {
      IUpgradeSearcher searcher = new UpgradeSearcher();
      upgrades.addAll(searcher.search());
    }
    return upgrades;
  }

  private static void printError() {
    System.out.println("Usage: UpgEntry <configurationFiles> [upgradeClassName] [initData]");
    System.out.println("e.g 1) /rumba.xml;/myrumba.xml");
    System.out.println("    2) /rumba.xml;/myrumba.xml com.hd123.rumba.upgrade.v20.r00.RB_v00r00");
    System.out.println("    3) /rumba.xml;/myrumba.xml "
        + "com.hd123.rumba.upgrade.v20.r00.RB_v00r00 initData");
  }

  private static String fetchDBMS() throws Exception {
    Configuration config = new Configuration().configure(com.hd123.rumba.runtime.Configuration
        .getInstance().getBusinessDoc());
    String driverClass = config.getProperty("hibernate.connection.driver_class");
    return (String) CUpgrade.DBMS_DRIVER_MAP.get(driverClass);
  }
}
